﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;

namespace Meow.Core
{
    /// <summary>
    /// A static class to gets informations about the screen.
    /// </summary>
    public static class Screen
    {
        public static event Action<int, int> ScreenSizeChanged = null;

        /// <summary>
        /// Gets the rectangle that represent the screen size
        /// </summary>
        public static Rectangle ScreenRect { get; internal set; }

        public static float AspectRatio => (float)Width / (float)Height;

        public static bool Fullscreen
        {
            get { return Application.GraphicsDeviceManager.IsFullScreen; }
            set
            {
                if (Application.GraphicsDeviceManager.IsFullScreen != value)
                    SetFullscreen(value);
            }
        }

        /// <summary>
        /// Gets the height of the screen (this value is cached so you can use it safely).
        /// </summary>
        public static int Width => ScreenRect.Width;

        /// <summary>
        /// Gets the height of the screen (this value is cached so you can use it safely).
        /// </summary>
        public static int Height => ScreenRect.Height;

        /// <summary>
        /// Gets the half-width of the screen (this value is cached so you can use it safely).
        /// </summary>
        public static int WidthPerTwo { get; internal set; }

        /// <summary>
        /// Gets the half-height of the screen (this value is cached so you can use it safely).
        /// </summary>
        public static int HeightPerTwo { get; internal set; }

        /// <summary>
        /// Gets the virtual screen rectangle.
        /// </summary>
        public static Rectangle VirtualScreenRect { get; internal set; }

        /// <summary>
        /// The virtual width of the screen.
        /// </summary>
        public static int VirtualWidth => VirtualScreenRect.Width;

        /// <summary>
        /// The virtual height of the screen.
        /// </summary>
        public static int VirtualHeight => VirtualScreenRect.Height;

        /// <summary>
        /// Show or hide the mouse cursor.
        /// </summary>
        public static bool ShowCursor
        {
            get => Application.Engine.IsMouseVisible;
            set => Application.Engine.IsMouseVisible = value;
        }

        /// <summary>
        /// Setup the helper.
        /// </summary>
        /// <param name="width">The width of the screen.</param>
        /// <param name="height">The height of the screen.</param>
        /// <param name="lockCursor">Indicates whether the cursor is locked.</param>
        /// <param name="showCursor">Indicates whether the cursor is visible.</param>
        public static void Setup(int width, int height, bool? lockCursor, bool? showCursor)
        {
            ScreenRect = new Rectangle(0, 0, width, height);

            WidthPerTwo = width >> 1;
            HeightPerTwo = height >> 1;

            if (showCursor.HasValue)
                ShowCursor = showCursor.Value;

            ScreenSizeChanged?.Invoke(width, height);
        }

        public static void SetVirtualResolution(int width, int height, bool applyToGUI = true)
        {
            VirtualScreenRect = GetRenderTargetDestination(new Point(width, height), GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width, GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height);

            //if (applyToGUI)
            //    GUI.Scale = GetScale();
        }

        static Rectangle GetRenderTargetDestination(Point resolution, int preferredBackBufferWidth, int preferredBackBufferHeight)
        {
            float resolutionRatio = (float)resolution.X / resolution.Y;
            float screenRatio;
            Point bounds = new Point(preferredBackBufferWidth, preferredBackBufferHeight);
            screenRatio = (float)bounds.X / bounds.Y;
            float scale;
            Rectangle rectangle = new Rectangle();

            if (resolutionRatio < screenRatio)
                scale = (float)bounds.Y / resolution.Y;
            else if (resolutionRatio > screenRatio)
                scale = (float)bounds.X / resolution.X;
            else
            {
                // Resolution and window/screen share aspect ratio
                rectangle.Size = bounds;
                return rectangle;
            }
            rectangle.Width = (int)(resolution.X * scale);
            rectangle.Height = (int)(resolution.Y * scale);
            return CenterRectangle(new Rectangle(Point.Zero, bounds), rectangle);
        }

        static Rectangle CenterRectangle(Rectangle outerRectangle, Rectangle innerRectangle)
        {
            Point delta = outerRectangle.Center - innerRectangle.Center;
            innerRectangle.Offset(delta);
            return innerRectangle;
        }

        /// <summary>
        /// Determines the max resolution.
        /// </summary>
        /// <param name="fullscreen">If set to <c>true</c> fullscreen.</param>
        public static void SetBestResolution(bool fullscreen)
        {
            var graphics = Application.GraphicsDevice;
            var modes = graphics.Adapter.SupportedDisplayModes;
            var width = 800;
            var height = 480;

            width = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;
            height = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;
            // Console.WriteLine("Base resolution as: " + width + " x " + height);

            if (!fullscreen)
            {
                width -= width / 16;
                height -= height / 12;
            }
            // Console.WriteLine("Set resolution as: " + width + " x " + height);
            SetResolution(width, height, fullscreen);
        }

        public static void SetResolution(int width, int height, bool fullscreen)
        {
            var gdm = Application.GraphicsDeviceManager;

            if (fullscreen)
            {
                width = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;
                height = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;
                gdm.HardwareModeSwitch = false;
            }

            gdm.PreferredBackBufferWidth = width;
            gdm.PreferredBackBufferHeight = height;

            gdm.IsFullScreen = fullscreen;
            gdm.ApplyChanges();


            Setup(width, height, null, null);

            //SetVirtualResolution(width, height, false);
            //GUI.Scale = GetScale();
        }

        /// <summary>
        /// Toggles fullscreen/windowed mode.
        /// </summary>
        public static void SetFullscreen(bool value)
        {
            Application.Engine.mainSettings.FullScreen = value;
            SetResolution(Application.Engine.mainSettings.WindowWidth, Application.Engine.mainSettings.WindowHeight, value);
            //Application.GraphicsDeviceManager.ToggleFullScreen();
        }

        public static void SaveSettings()
        {
            Application.Engine.mainSettings.WindowWidth = Width;
            Application.Engine.mainSettings.WindowHeight = Height;
            Application.Engine.mainSettings.FullScreen = Fullscreen;
        }
    }
}
